package com.yuanda.wordhot.util;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuanda.wordhot.exception.BusinessException;

/**
 * 封装关于JSON字符串的操作，依赖JackSon JSON jar包
 * 
 * @author YuBai
 * 
 */
public final class JsonUtils {
	public static final String PATH_SPLIT_STR = ":";// 路径分隔符
	private static ObjectMapper mapper = null;// 提供对象与JSON之间的相互转换

	static {
		mapper = getMapperInstance(false);
	}

	/**
	 * 获取ObjectMapper
	 * ObjectMapper创建需要消耗许多资源，所以一般建议只创建一次。ObjectMapper是线程安全的，所以可以放心在多线程环境下使用。
	 * 
	 * @param isCreateNew
	 *            是否创建新的ObjectMapper
	 * @return
	 */
	public static ObjectMapper getMapperInstance(boolean isCreateNew) {
		if (isCreateNew) {
			return new ObjectMapper();
		} else if (mapper == null) {
			synchronized (JsonUtils.class) {
				if (mapper == null) {
					mapper = new ObjectMapper();
					mapper.setDateFormat(new SimpleDateFormat(
							GlobalConstants.DateFormatKeys.DATE_10_FORMAT));
				}
			}
		}

		return mapper;
	}

	/**
	 * 用于生成JSON字符串，这里Object可以为常见的对象类型
	 * 如：Bean\List<Bean>\Map<String,String>\Map<String,Bean>
	 * 
	 * @param obj
	 *            进行转换的对象
	 * @return JSON字符串
	 */
	public static String generateJsonByObject(Object obj) {
		String jsonStr = null;
		try {
			jsonStr = mapper.writeValueAsString(obj);
		} catch (JsonProcessingException e) {
			throw new BusinessException("json process exception!", e);
		}
		return jsonStr;
	}

	/**
	 * 根据JSON转换成bean
	 * 
	 * @param jsonStr
	 *            JSON字符串
	 * @param cls
	 *            需要转换到的类类型
	 * @return
	 */
	public static <T> T toBean(String jsonStr, Class<T> cls) {
		T bean = null;
		try {
			bean = mapper.readValue(jsonStr, cls);
		} catch (JsonParseException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bean;
	}

	/**
	 * 根据路径获取值 路径使用:分隔符 如： person:father:name 如果找不到，或者路径为空 则返回null
	 * 
	 * @param jsonStr
	 *            JSON字符串
	 * @param tagPath
	 *            节点名称 中间用：分隔
	 * @return 取到值得集合
	 */
	public static List<String> getValuesFromJsonStrByPath(String jsonStr,
			String tagPath) {
		JsonNode node = null;
		try {
			node = mapper.readTree(jsonStr);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return getValuesFromJsonNodeByPath(node, tagPath);
	}

	/**
	 * 从指定的JsonNode的指定节点取值
	 * 
	 * @param node
	 * @param tagPath
	 * @return
	 */
	public static List<String> getValuesFromJsonNodeByPath(JsonNode node,
			String tagPath) {
		if (isNodeNull(node) || (StringUtils.isBlank(tagPath))) {
			return null;
		}
		// 返回值
		List<String> value = new ArrayList<String>();
		String[] path = tagPath.split(PATH_SPLIT_STR);
		getJsonValues(node, path, value, 1);
		return value;
	}

	/**
	 * getValueFromJsonNodeByPath 调用的一个私有方法 传入参数的时候要保证每一个参数都不为空 否则会报空指针异常
	 * 
	 * @param node
	 * @param path
	 * @param values
	 * @param nextIndex
	 */
	private static void getJsonValues(JsonNode node, String[] path,
			List<String> values, int nextIndex) {
		// 是路径的最后就直接取值
		if (nextIndex == path.length) {
			if (node.isArray()) {
				for (int i = 0; i < node.size(); i++) {
					JsonNode child = node.get(i).get(path[nextIndex - 1]);
					if (isNodeNull(child)) {
						continue;
					}
					values.add(parseValue(child));
				}
			} else {
				JsonNode child = node.get(path[nextIndex - 1]);
				if (!isNodeNull(child)) {
					values.add(parseValue(child));
				}
			}
			return;
		}
		// 判断是Node下是集合还是一个节点
		node = node.get(path[nextIndex - 1]);
		if (isNodeNull(node)) {
			return;
		}
		if (node.isArray()) {
			for (int i = 0; i < node.size(); i++) {
				getJsonValues(node.get(i), path, values, nextIndex + 1);
			}
		} else {
			getJsonValues(node, path, values, nextIndex + 1);
		}
	}

	/**
	 * 从Node中解析值 因为Node可能是个大节点下面还包含子元素 如果再用getTextValue那么取不到值
	 * 如果都用toString()那么如果当前节点就是个值节点 那么会在值上加双引号
	 * 
	 * @param child
	 * @return
	 */
	private static String parseValue(JsonNode node) {
		if (node.isValueNode()) {
			return node.textValue();
		}
		return node.toString();
	}

	/**
	 * 判断Node是否为空
	 * 
	 * @param node
	 * @return
	 */
	public static boolean isNodeNull(JsonNode node) {
		if ((node == null) || node.isNull()) {
			return true;
		}
		if (node.isArray()) {
			// 如果Node是集合 下面如果没有子节点也
			if (node.size() < 1) {
				return true;
			}
		}
		return false;
	}
}
